﻿using Asp.Versioning;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.IdentityModel.Tokens;
using NUglify.Helpers;
using System.IdentityModel.Tokens.Jwt;
using Volo.Abp.Authorization;

namespace FlyingEye.Controllers
{

    [Authorize]
    [ControllerName("Signature")]
    [ApiVersion("1.0")]
    [Route("api/device-app-service/v{version:apiVersion}/signatures")]
    public class SignatureController : DefaultController
    {
        private readonly IConfiguration _configuration;

        public SignatureController(IConfiguration configuration)
        {
            this._configuration = configuration;
        }

        [HttpPost("add-claims")]
        public async Task<OkObjectResult> AddClaims([FromBody] CreateAddClaimsRequest request)
        {
            return await this.GetInvokeAsync(async () =>
            {
                return await Task.FromResult(new { AccessToken = CreateNewAccessToken(request) });
            });
        }

        /// <summary>
        /// 创建新的访问令牌
        /// </summary>
        private string CreateNewAccessToken(CreateAddClaimsRequest request)
        {
            // 设置应用程序启动路径，一定是基于主函数所在的模块作为启动路径。
            var startPath = Path.GetDirectoryName(typeof(DeviceAppServiceModule).Assembly.Location);

            if (string.IsNullOrWhiteSpace(startPath) || !Directory.Exists(startPath))
            {
                throw new InvalidOperationException("无效的启动路径！");
            }

            var jwkFile = Path.Combine(startPath, _configuration["SigningKey:Path"] ??
                throw new InvalidOperationException("The SigningKey:Path is null or empty."));

            if (!System.IO.File.Exists(jwkFile)) throw new InvalidOperationException($"{jwkFile} is not found.");

            var jsonString = System.IO.File.ReadAllText(jwkFile);
            var jwk = new Microsoft.IdentityModel.Tokens.JsonWebKey(jsonString);

            if (this.HttpContext.Request.Headers.TryGetValue("Authorization", out var tokenFromHeader))
            {
                var accessToken = tokenFromHeader.ToString().Remove(0, "Bearer ".Length);
                JwtSecurityTokenHandler jwtSecurityTokenHandler = new JwtSecurityTokenHandler();
                var originalToken = jwtSecurityTokenHandler.ReadJwtToken(accessToken);

                request.Claims.ForEach(item =>
                {
                    originalToken.Payload.Add(item.Key, item.Value);
                });

                JwtSecurityToken jwtSecurityToken = new JwtSecurityToken(
                   new JwtHeader(new SigningCredentials(jwk, SecurityAlgorithms.RsaSha256), new Dictionary<string, string>(), "at+jwt"),
                   originalToken.Payload);

                var token = jwtSecurityTokenHandler.WriteToken(jwtSecurityToken);

                return token;
            }
            else
            {
                throw new AbpAuthorizationException();
            }
        }
    }
}
